/*
 *    Copyright 2022 CManLH
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package com.lifeonwalden.ms.web.site;

import com.lifeonwalden.ms.common.logger.LoggerUtil;
import org.apache.logging.log4j.Logger;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.session.SessionHandler;
import org.eclipse.jetty.servlet.ErrorPageErrorHandler;
import org.eclipse.jetty.servlet.FilterHolder;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.XmlWebApplicationContext;
import org.springframework.web.filter.DelegatingFilterProxy;
import org.springframework.web.servlet.DispatcherServlet;

import javax.servlet.DispatcherType;
import java.util.EnumSet;

public class ServletServer {
    private final static Logger logger = LoggerUtil.getLogger(ServletServer.class);

    private boolean withAuthModule = false;

    private boolean secureCookies = false;

    private int cookieMaxAge = -1;

    private static final String MAPPING_URL = "/*";

    // port of servlet service
    private int port = 8080;

    private String contextPath = "/";

    public ServletServer setPort(int port) {
        this.port = port;
        return this;
    }

    public ServletServer setContextPath(String contextPath) {
        this.contextPath = contextPath;
        return this;
    }

    public ServletServer setWithAuthModule(boolean withAuthModule) {
        this.withAuthModule = withAuthModule;
        return this;
    }

    public ServletServer setSecureCookies(boolean secureCookies) {
        this.secureCookies = secureCookies;
        return this;
    }

    public ServletServer setCookieMaxAge(int cookieMaxAge) {
        this.cookieMaxAge = cookieMaxAge;
        return this;
    }

    public void run() throws Exception {
        Server server = new Server(port);
        server.setHandler(servletContextHandler(webApplicationContext()));
        server.start();
        server.join();
    }

    private DelegatingFilterProxy shiroAuthFilter() {
        DelegatingFilterProxy delegatingFilterProxy = new DelegatingFilterProxy();
        delegatingFilterProxy.setTargetBeanName("shiroAuthFilter");
        delegatingFilterProxy.setTargetFilterLifecycle(true);

        return delegatingFilterProxy;
    }

    private ServletContextHandler servletContextHandler(WebApplicationContext context) {
        ServletContextHandler handler = new ServletContextHandler();
        handler.setContextPath(contextPath);
        if (withAuthModule) {
            handler.addFilter(new FilterHolder(shiroAuthFilter()), "/*", EnumSet.allOf(DispatcherType.class));
        }

        ServletHolder servletHolder = new ServletHolder(new DispatcherServlet(context));
        servletHolder.setInitOrder(1);
        handler.addServlet(servletHolder, MAPPING_URL);
        handler.addEventListener(new ContextLoaderListener(context));
        SessionHandler sessionHandler = new SessionHandler();
        sessionHandler.getSessionCookieConfig().setSecure(secureCookies);
        sessionHandler.getSessionCookieConfig().setMaxAge(cookieMaxAge);
        handler.setSessionHandler(sessionHandler);

        ErrorPageErrorHandler errorPageErrorHandler = new ErrorPageErrorHandler();
        errorPageErrorHandler.addErrorPage(404, "open/error404.do");
        errorPageErrorHandler.addErrorPage(500, "open/error500.do");
        return handler;
    }

    private WebApplicationContext webApplicationContext() {
        XmlWebApplicationContext xmlWebApplicationContext = new XmlWebApplicationContext();
        xmlWebApplicationContext.setConfigLocation("classpath*:app.xml");

        return xmlWebApplicationContext;
    }
}
